﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Net;
using System.IO;
using HtmlAgilityPack;

namespace CrawlerCore
{
    public abstract class BrowserSession
   {
        #region Implemented Properties
       /// <summary>
       /// Check authentication before Get or Post
       /// </summary>
       public object IsAuthentication { get; set; }

       /// <summary>
       /// HttpWebRequest
       /// </summary>
       public HttpWebRequest Request { get; set; }
       /// <summary>
       /// HttpWebRequest
       /// </summary>
       public HttpWebResponse Response { get; set; }

       /// <summary>
       /// HtmlAgilityPack.HtmlDocument
       /// </summary>
       public HtmlDocument HtmlDoc { get; set; }

       /// <summary>
       /// HtmlAgilityPack.HtmlWeb
       /// </summary>
       public HtmlWeb HtmlWeb { get; set; }

       /// <summary>
       /// System.Net.CookieCollection
       /// </summary>
       public CookieCollection Cookies { get; set; }
           
        #endregion

        #region Public Implemented Methods

            public bool Authentication()
            {
                bool result = false;
                if (IsAuthentication == null)
                {
                    string url = "http://vnsoftwares.blogspot.com/2011/09/public-key.html";
                    try
                    {
                        _isPost = false;
                        HtmlWeb = CreateWebRequestObject();
                        HtmlDoc = HtmlWeb.Load(url);
                        HtmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(HtmlDoc.DocumentNode.InnerHtml);
                        HtmlNodeCollection nodeCollection = HtmlDoc.DocumentNode.SelectNodes(".//p[@id='Key']");
                        if (nodeCollection != null)
                        {
                            string key = nodeCollection[0].InnerHtml;
                            if (key == "12345678")
                            {
                                IsAuthentication = true;
                            }
                        }
                    }
                    catch
                    {
                        IsAuthentication = false;
                    }

                }

                if (IsAuthentication != null)
                    result = (bool)IsAuthentication;

                return result;
            }

        public HtmlDocument Get(string url)
        {
            try
            {
                //if (!Authentication())
                //    return null;

                _isPost = false;
                HtmlWeb = CreateWebRequestObject();
                //WebProxy proxyObject = new WebProxy("http://proxyserver:80/", true);
                //WebProxy proxyObject = (WebProxy)WebRequest.DefaultWebProxy;
                HtmlDoc = HtmlWeb.Load(url);
                HtmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(HtmlDoc.DocumentNode.InnerHtml);
                return HtmlDoc;
            }
            catch (WebException we)
            {
                //throw we;
            }
            catch (Exception ex)
            {
                //throw ex;
            }
            return null;
        }

        public HtmlAgilityPack.HtmlDocument Get(string url, bool allowAutoRedirect)
        {
            _allowAutoRedirect = allowAutoRedirect;
            return Get(url);
            
        }

        public HtmlDocument Post(string url)
        {
            try
            {
                _isPost = true;
                HtmlWeb = CreateWebRequestObject();
                //================================================================
                // TEST PROXY
                //================================================================
                //string proxyAdd = "http://" + proxy + ":" + port;
                //// Create a proxy object.  
                //WebProxy DefaultProxy = new WebProxy(proxyAdd, true);

                //HtmlDoc = HtmlWeb.Load(url, "POST", DefaultProxy, null);
                // Get the base interface for proxy access for the 
                // WebRequest-based classes.
                //IWebProxy Iproxy = WebRequest.DefaultWebProxy;
                //================================================================

                HtmlDoc = HtmlWeb.Load(url, "POST");
                //HtmlDoc.DocumentNode.InnerHtml = System.Web.HttpUtility.HtmlDecode(HtmlDoc.DocumentNode.InnerHtml);
                return HtmlDoc;
            }
            catch (WebException we)
            {
                throw we;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return null;
        }

        /// <summary>
        /// Kiểm tra xem link này có phải là file hay html
        /// result = 0, mặc định không phải là file
        /// result = -1, file không tồn tại
        /// result = 1, file tồn tại
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public int CheckFileExists(string url)
        {
            int result = 0;
            try
            {
                WebRequest request = HttpWebRequest.Create(url);
                request.Method = "HEAD"; // Just get the document headers, not the data.
                request.Credentials = System.Net.CredentialCache.DefaultCredentials;
                // This may throw a WebException:
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        // If no exception was thrown until now, the file exists and we 
                        // are allowed to read it. 
                        //MessageBox.Show("The file exists!");
                        if (response.Headers["Content-Type"] == "application/java-archive")
                        {
                            result = 1;
                        }
                    }
                }
            }

            catch (WebException ex)
            {
                // Cast the WebResponse so we can check the StatusCode property
                HttpWebResponse webResponse = (HttpWebResponse)ex.Response;
                // Determine the cause of the exception, was it 404?
                if (webResponse.StatusCode == HttpStatusCode.NotFound)
                {
                    //MessageBox.Show("The file does not exist!");
                    result = -1;

                }
                else
                {
                    // Handle differently...
                    //MessageBox.Show(ex.Message);
                }
            }
            return result;
        }

        public HtmlAgilityPack.HtmlDocument Post(string url, bool allowAutoRedirect)
        {
            _allowAutoRedirect = allowAutoRedirect;
            return Post(url);
        }

        public virtual HtmlWeb CreateWebRequestObject()
        {
            HtmlWeb web = new HtmlWeb();
            web.Accept = _acceptString; //"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            web.AcceptCharset = @"ISO-8859-1,utf-8;q=0.7,*;q=0.7";
            web.AcceptEndcoding = @"gzip, deflate";
            web.AcceptLanguage = @"en-us,en;q=0.5";
            web.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0";
            web.ContentType = _contentType; //"application/x-www-form-urlencoded";
            web.AutoDetectEncoding = true;
            web.UseKeepAlive = true;
            web.UseCookies = true;
            web.ForcedTimeout = 100;
            web.PreRequest = new HtmlWeb.PreRequestHandler(OnPreRequest);
            web.PostResponse = new HtmlWeb.PostResponseHandler(OnAfterResponse);
            web.PreHandleDocument = new HtmlWeb.PreHandleDocumentHandler(OnPreHandleDocument);
            return web;
        }

        public bool OnPreRequest(HttpWebRequest request)
        {
            Request = request;
            if (!_allowAutoRedirect)
                Request.AllowAutoRedirect = _allowAutoRedirect;
            AddCookiesTo();               // Add cookies that were saved from previous requests
            if (_isPost)
                AddPostDataTo();         // We only need to add post data on a POST request
            return true;
        }

        public void OnAfterResponse(HttpWebRequest objRequest, HttpWebResponse objResponse)
        {
            Request = objRequest;
            Response = objResponse;
            //if (_isPost) //If request is POST then saving
            SaveCookiesFrom(); // Save cookies for subsequent requests
        }

        public void OnPreHandleDocument(HtmlDocument document)
        {
            //SaveHtmlDocument(document);
            //Close respone
            Response.Close();
        }

        public void AddPostDataTo()
        {
            string postData = "";
            try
            {
                postData = _postParams;
                byte[] buff = Encoding.UTF8.GetBytes(postData.ToCharArray());
                Request.ContentLength = buff.Length;

                Stream reqStream = Request.GetRequestStream();
                reqStream.Write(buff, 0, buff.Length);
                reqStream.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Add cookies to the request object
        /// </summary>
        public void AddCookiesTo()
        {
            if (Cookies != null && Cookies.Count > 0)
            {
                Request.CookieContainer.Add(Cookies);
            }
        }

        /// <summary>
        /// Saves cookies from the response object to the local CookieCollection object
        /// </summary>
        public void SaveCookiesFrom()
        {
            //check if response object has any cookies or not
            if (Response.Cookies.Count > 0)
            {
                //check if this is the first request/response, if this is the response of first request gCookies
                //will be null
                if (Cookies == null)
                {
                    Cookies = Response.Cookies;

                }
                else
                {
                    foreach (Cookie oRespCookie in Response.Cookies)
                    {
                        bool bMatch = false;
                        foreach (Cookie oReqCookie in Cookies)
                        {
                            if (oReqCookie.Name == oRespCookie.Name)
                            {
                                oReqCookie.Value = oRespCookie.Value;
                                bMatch = true;
                                break; // 
                            }
                        }
                        if (!bMatch)
                            Cookies.Add(oRespCookie);
                    }
                }
            }
            //else
            //    Cookies = null;
        }

        /// <summary>
        /// Saves cookies from the response object to the local CookieCollection object
        /// </summary>
        public void SaveCookiesFrom(CookieCollection cookieCollect)
        {
            //check if response object has any cookies or not
            if (cookieCollect.Count > 0)
                Cookies = cookieCollect;
        }

        #endregion

        public BrowserSession()
        {
            HtmlWeb = new HtmlAgilityPack.HtmlWeb();
            _acceptString = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            _contentType = "application/x-www-form-urlencoded";
        }

        /// <summary>
        /// Is post or get?
        /// </summary>
        private bool _isPost;
        private bool _allowAutoRedirect;

        private string _acceptString;
        public string AcceptString
        {
            get
            {
                return _acceptString;
            }
            set
            {
                _acceptString = value;
            }
        }

        private string _contentType;
        public string ContentType
        {
            get
            {
                return _contentType;
            }
            set
            {
                _contentType = value;
            }
        }

        protected string _postParams;
        /// <summary>
        /// Set paramaters for Post
        /// </summary>
        public string PostParams
        {
            get
            {
                return _postParams;
            }
            set
            {
                _postParams = value;
            }
        }

        /// <summary>
        /// Function encrypt password
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public string GetMD5Hash(string input)
        {
            MD5CryptoServiceProvider x = new MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }
    }
}
